/*
 * Departamento de Ciência da Computação
 * Tradutores 02/2009 - turma A
 * Professor Marco Aurélio
 * Alunos: Danilo Gaby Andersen Trindade - 06/82039
 *         Alex Rodrigo de Oliveira      - 06/30403
 */

#include <cstdlib>
#include "tipos.h"
#include "code.h"
#include "actions.h"

using namespace std;

static table globaltable, scopetable;

static void error(const char *txt);


/*
 * Só chama o init do gerador.
 */
void act_init() {
    cod_init();
}


/*
 * Só chama o end do gerador.
 */
void act_end() {
    cod_end();
}


/*
 * Atribuição global só precisa gerar o código.
 */
int act_atr(int lval, int exp, char tp) {
    return cod_move(lval, exp, tp);
}


/*
 * Garante que não existe um global com esse nome e cria um.
 */
int act_lval_id0(char *lex) {
    string id(lex);
    
    int i;
    if ( (i = globaltable.find(id)) != -1 ) {
        error("a global variable with this name already exists");
    }
    
    int16_t pos = cod_reg0();
    symbol tmp = {id, pos};
    globaltable.push_back(tmp);
    return pos;
}


/*
 * Procura o registrador como esse lexema e retorna a posição dele.
 * Se não achar cria um.
 */
int act_lval_id1(char *lex) {
    string id(lex);
    
    int i;
    if ( (i = scopetable.find(id)) != -1 ) {
        return scopetable[i].pos;
    }
    
    int16_t pos = cod_reg1();
    symbol tmp = {id, pos};
    scopetable.push_back(tmp);
    return pos;
}


/*
 * Procura o registrador como esse lexema.
 * Pode dar erro, se não encontrar.
 */
int act_id(char *lex) {
    string id(lex);
    
    int i;
    if ( (i = scopetable.find(id)) != -1 ) {
        return scopetable[i].pos;
    }
    
    error("a variable with this name do not exists");
    return -1;
}


/*
 * Só gerar código.
 */
int act_exp_eq(int a1, int a2) {
    return cod_eq(a1, a2);
}

int act_exp_lt(int a1, int a2) {
    return cod_lt(a1, a2);
}

int act_exp_gt(int a1, int a2) {
    return cod_gt(a1, a2);
}

int act_exp_le(int a1, int a2) {
    return cod_le(a1, a2);
}

int act_exp_ge(int a1, int a2) {
    return cod_ge(a1, a2);
}

int act_exp_ne(int a1, int a2) {
    return cod_ne(a1, a2);
}

int act_exp_add(int a1, int a2) {
    return cod_add(a1, a2);
}

int act_exp_sub(int a1, int a2) {
    return cod_sub(a1, a2);
}

int act_exp_mult(int a1, int a2) {
    return cod_mult(a1, a2);
}

int act_exp_mod(int a1, int a2) {
    return cod_mod(a1, a2);
}

int act_exp_div(int a1, int a2) {
    return cod_div(a1, a2);
}


/*
 * Só gerar código.
 */
int act_atom_int(int val) {
    return cod_imm(val);
}


/*
 * Já terminamos o parse de todos os comandos dentro da função.
 * Só gera o código.
 */
int act_fn() {
    return cod_fn_end();
}


/*
 * Vamos começar uma nova função, prepara a tabela, o frame e o box.
 */
int act_fn_id(const char *lex) {
    scopetable.clear();
    
    string id(lex);
    if (globaltable.find(id) != -1) {
        error("a function with this name already exists");
    }
    
    int16_t pos = cod_fn();
    symbol sym = {id, pos};
    globaltable.push_back(sym);
    return pos;
}


/*
 * Acrescenta um parâmetro na tabela de escopo.
 */
int act_param(char *lex) {
    string id(lex);
    int16_t pos = cod_reg1();
    symbol tmp = {id, pos};
    scopetable.push_back(tmp);
    return pos;
}






/*
 * Imprime a mensagem de erro semântico e sai.
 */
static void error(const char *txt) {
    fprintf(stderr, "semantic error on line %d, %s.\n", here, txt);
    exit(1);
}
